package redis

import (
	"errors"
	"strconv"
	"time"

	"github.com/go-redis/redis"
)

//投票功能:

/* 投票的几种情况
direction = 1 , 两种情况:
	1.之前没投过 , 现在投赞成
	2.之前投反对 , 现在改赞成
direction = 0 , 两种情况:
	1.之前投赞成 , 现在取消投票
	2.之前投反对 , 现在取消投票
direction = -1 , 两种情况:
	1.之前没投过 , 现在投反对
	2.之前投赞成 , 现在改反对

投票的限制:
每个帖子自发表之日起一个星期之内允许用户投票
	1.到期之后将redis中保存的赞成票及反对票存储到mysql表中。
	2.到期后删除那个KeyPostVotedZSetPF
*/

const (
	oneWeekInSeconds = 7 * 24 * 3600
	scorePerVote     = 432 // 每一票的分值
)

var (
	ErrVoteTimeExpire = errors.New("投票时间已过")
)

func CreatePost(pid, cid int64) error {

	pipeline := rdb.TxPipeline() //事务操作, 下面两个添加元素必须一起成功或失败
	//帖子时间
	pipeline.ZAdd(getRedisKey(KeyPostTimeZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: pid,
	})
	//帖子分数
	pipeline.ZAdd(getRedisKey(KeyPostScoreZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: pid,
	})
	// 把帖子id加到社区的set里
	cKey := getRedisKey(KeyCommunyityZSetPF + strconv.Itoa(int(cid)))
	pipeline.ZAdd(cKey, redis.Z{
		Score:  0,
		Member: pid,
	})
	_, err := pipeline.Exec()
	return err
}

func VoteForPost(userID, postID string, direction float64) error {
	// 1. 判断投票限制
	// 取redis取帖子发布时间
	postTime := rdb.ZScore(getRedisKey(KeyPostTimeZSet), postID).Val()
	if float64(time.Now().Unix())-postTime > oneWeekInSeconds {
		return ErrVoteTimeExpire
	}

	// 2. 更新帖子分数
	// 先查当前用户给当前帖子的投票纪录
	ov := rdb.ZScore(getRedisKey(KeyPostVotedZSetPF+postID), userID).Val()
	diff := direction - ov //计算两次投票的差值

	//设置事务, 更新帖子分数和用户为帖子投票数据需要一起成功失败
	pipeline := rdb.TxPipeline()
	pipeline.ZIncrBy(getRedisKey(KeyPostScoreZSet), diff*scorePerVote, postID)
	// 3。记录用户为该帖子投票的数据
	if direction == 0 { // 取消投票
		pipeline.ZRem(getRedisKey(KeyPostVotedZSetPF+postID), userID)
	} else {
		pipeline.ZAdd(getRedisKey(KeyPostVotedZSetPF+postID), redis.Z{
			Score:  direction,
			Member: userID,
		}) //ZAdd给有序集合加一个特定类型的元素(redis.Z)
	}
	_, err := pipeline.Exec()
	return err
}
